package com.blade.common.utils;

import com.blade.helper.Money;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;

/**
 * 由于Java的简单类型不能够精确的对浮点数进行运算，这个工具类提供精
 * 确的浮点数运算，包括加减乘除和四舍五入。
 * 并提供数字的格式化操作，方便用于金钱类数字格式化，double直接操作问题多
 * 比如21.000只会输出21.0等问题
 */
public class ArithUtil {
    /**
     * 默认除法运算精度
     */
    private static final int DEF_DIV_SCALE = 10;

    /**
     * 这个类不能实例化
     */
    private ArithUtil(){}

    /**
     * 提供精确的加法运算。
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.add(b2).doubleValue();
    }
    /**
     * 提供精确的减法运算。
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double subtract(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.subtract(b2).doubleValue();
    }
    /**
     * 提供精确的乘法运算。
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double multiply(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到
     * 小数点以后10位，以后的数字四舍五入。
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double divide(double v1,double v2){
        return divide(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指
     * 定精度，以后的数字四舍五入。 BigDecimal.ROUND_HALF_UP就是标准的四舍五入的模式
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double divide(double v1, double v2, int scale){
        if(scale<0){
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }

        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.divide(b2,scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理。
     * round和上面divide的四舍五入scale作为参数传给divide一样可以
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale){
        if(scale<0){
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }

        return new BigDecimal(Double.toString(v)).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }


    /**
     * 将指定的double数字按照0.00的格式来四舍五入后格式化输出数字字符串
     * @param value 需要格式化的数字
     * @return 四舍五入后格式化输出数字字符串
     * 0.00 : 0表示如果没有则该位补0
     * 也就是个位是有一个数字，小数部分保留到百分位小数的四舍五入
     */
    public static String formatNumber(double value){
        /*
         * 默认格式，0.00表示数据按照这样的格式，去格式化，0表示如果没有则该位补0.
         * 比如0.4，格式化就是0.40
         * 如果是000.000，值是4.14，那么格式化后就是004.140
         */
        String pattern = "0.00";

        return formatNumber(pattern, value);
    }

    /**
     * 将指定的double数字格式化按照指定的格式，四舍五入格式化输出数字字符串
     * @param pattern 指定的格式 如 ##.## : #表示没有则为空，　0.00 : 0表示如果没有则该位补0
     * @param value 需要格式化输出的double值
     * @return 格式化后输出的数字字符串
     */
    public static String  formatNumber(String pattern, double value){
        DecimalFormat df=new DecimalFormat(pattern);
        df.setRoundingMode(RoundingMode.HALF_UP);
         return df.format(value);
    }

    public static void main(String[] strings) {
//        // 保留3位小数
//        System.out.println(ArithUtil.round(0.2410, 3));
//
//        // 保留3位小数
//        System.out.println(ArithUtil.round(0.2400, 3));
//
//        // 保留4位小数
//        System.out.println(ArithUtil.round(0.2400000, 4));
//
////         保留2位小数
////         setScale来四舍五入，并不会补0，当0.20保留两位，或者0.200保留两位，末尾的0会舍去，这个就会出现不是两位小数的情况
//        System.out.println(ArithUtil.round(0.20, 2));
//
//        System.out.println(new Money(50).toString());

//        ArithUtil.formatNumber("##.##", 535);
//        ArithUtil.formatNumber("0.00", 0.535);
//        ArithUtil.formatNumber("00000.00", 2.6);
//        ArithUtil.formatNumber("###,###.###", 111222.3004567000000);
//        ArithUtil.formatNumber("000,000.000", 11222.34567);
//        ArithUtil.formatNumber("###,###.###$", 111222.34567);
//        ArithUtil.formatNumber("000,000.000￥", 11222.34567);
//        ArithUtil.formatNumber("##.###%", 0.345678);        // 使用百分数形式
//        ArithUtil.formatNumber("00.###%", 0.0345678);        // 使用百分数形式
//        ArithUtil.formatNumber("###.###\u2030", 0.345678);    // 使用千分数形式

        System.out.println(new Money(50).toString());


    }
}
